<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
  <style>
    body,
    html {
      height: 100vh;
    }
  </style>
</head>

<body>
  <canvas id="c"></canvas>
  <script type="text/javascript">

    ; (function () {


      'use strict';

      var c = document.getElementById('c');

      var ctx = c.getContext('2d');

      var w = c.width = window.innerWidth;

      var h = c.height = window.innerHeight;

      var cx = w / 2;

      var cy = h / 2;

      var fl = 1000;

      function prj(obj) {


        var cz = obj.z + fl;

        if (cz === 0) return;

        var scl = fl / cz;

        obj.p.x = cx + obj.x * scl;

        obj.p.y = cy + obj.y * scl;

        obj.s = scl;

      }

      var P = function (x, y, z) {


        this.x = x;

        this.y = y;

        this.z = z;

        this.s = 1;

        this.cl = 0;

        this.p = {


          x: 0,

          y: 0

        };

      };

      P.prototype = {


        constructor: P,

        update: function () {


          this.z -= 30;

        },

        render: function (ctx) {


          if (this.z <= -fl) return;

          ctx.save();

          ctx.translate(this.p.x, this.p.y);

          ctx.scale(this.s, this.s);

          ctx.fillStyle = 'hsla(' + this.cl + ', 100%, 50%, 0.5)';

          ctx.beginPath();

          ctx.arc(0, 0, 2, 0, Math.PI * 2);

          ctx.fill();

          ctx.restore();

        }

      };

      var M = function (x, y, z) {


        this.list = [];

        this.max = 100;

        this.x = x;

        this.y = y;

        this.z = z;

        this.s = 1;

        this.p = {


          x: 0,

          y: 0

        };

        this.ax = Math.random() * (Math.PI * 2);

        this.ay = Math.random() * (Math.PI * 2);

        this.rx = Math.random() * 100;

        this.ry = Math.random() * 100;

        this.cl = Math.random() * 360;

        this.cls = Math.random();

      };

      M.prototype = {


        constructor: M,

        update: function () {


          this.cl += this.cls;

          this.ax += Math.random() * 0.1 - 0.02;

          this.ay += Math.random() * 0.1 - 0.02;

          this.x = Math.cos(this.ax) * 100;

          this.y = Math.sin(this.ay) * 100;

          this.z += 10;

          if (this.z > fl) this.z = fl;

          if (this.list.length < this.max) {


            if (Math.random() * 100 < 50) {


              var pp = new P(this.x, this.y, this.z);

              pp.cl = this.cl;

              this.list.push(pp);

            }

          } else {


            var pp = this.list.shift();

            pp.x = this.x;

            pp.y = this.y;

            pp.z = this.z;

            pp.cl = this.cl;

            this.list.push(pp);

          }

        },

        render: function (ctx) {


          if (this.z <= -fl) return;

          ctx.save();

          ctx.translate(this.p.x, this.p.y);

          ctx.fillStyle = 'green';

          ctx.beginPath();

          ctx.arc(0, 0, 2, 0, Math.PI * 2);

          ctx.fill();

          ctx.restore();

        }

      };

      function update(mv, list) {


        for (var i = 0; i < list.length; i++) {


          var p = list[i];

          p.update();

          prj(p);

          p.render(ctx);

        }

        for (var i = list.length - 1; i >= 0; i--) {


          var p = list[i];

          if (p.z <= -fl) continue;

          if (i === list.length - 1) {


            ctx.lineWidth = Math.random();

            ctx.strokeStyle = 'hsl(' + mv.cl + ', 100%, 50%)';

            ctx.beginPath();

            ctx.moveTo(p.p.x, p.p.y);

          } else {


            ctx.lineTo(p.p.x, p.p.y);

          }

        }

        ctx.stroke();

      }

      var ms = [];

      for (var i = 0; i < 10; i++) {


        ms.push(new M(

          Math.random() * 400 - 200,

          Math.random() * 400 - 200,

          Math.random() * 400 - 200));

      }

      requestAnimationFrame(function loop() {


        requestAnimationFrame(loop);

        ctx.clearRect(0, 0, w, h);

        for (var i = 0; i < ms.length; i++) {


          var m = ms[i];

          m.update();

          prj(m);

          update(m, m.list);

        }

      });

    })();
  </script>
</body>

</html>